package com.ae.base.cap;

import com.ae.base.ModConfig;
import com.ae.base.block.PlacedItem;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.registries.ForgeRegistries;

import javax.annotation.Nonnull;
import java.util.function.BiConsumer;

public class SingleItemStackHandler implements IItemHandler, INBTSerializable<CompoundNBT> {
    protected ItemStack stack;
    protected int maxCount;
    //当库存变更时触发的行为，stack 存储的物品，integer 该物品堆能存储的最大数量
    protected BiConsumer<ItemStack, Integer> onContentsChanged;


    public SingleItemStackHandler(ItemStack stack, int count, BiConsumer<ItemStack, Integer> onContentsChanged) {
        this.stack = stack;
        this.maxCount = count;
        this.onContentsChanged = onContentsChanged;
    }

    @Override
    public int getSlots() {
        return 1;
    }

    /**
     * @param slot 无实际作用，任何值都返回同一个值
     * @return 存储的物品
     */
    @Nonnull
    @Override
    public ItemStack getStackInSlot(int slot) {
        return getStackInSlot();
    }

    public ItemStack getStackInSlot() {
        return stack;
    }

    @Nonnull
    @Override
    public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
        return insertItem(stack, simulate);
    }

    public ItemStack insertItem(@Nonnull ItemStack stack, boolean simulate) {
        if (stack.isEmpty())
            return ItemStack.EMPTY;

        if (!isItemValid(stack))
            return stack;

        ItemStack existing = this.stack;

        int limit = this.maxCount;

        if (!existing.isEmpty()) {
            if (!ItemHandlerHelper.canItemStacksStack(stack, existing))
                return stack;

            limit -= existing.getCount();
        }

        if (limit <= 0)
            return stack;

        boolean reachedLimit = stack.getCount() > limit;

        if (!simulate) {
            if (existing.isEmpty()) {
                this.stack = reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, limit) : stack;
            } else {
                existing.grow(reachedLimit ? limit : stack.getCount());
            }
            onContentsChanged();
        }

        return reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - limit) : ItemStack.EMPTY;
    }

    @Nonnull
    @Override
    public ItemStack extractItem(int slot, int amount, boolean simulate) {
        return extractItem(amount, simulate);
    }

    public ItemStack extractItem(int amount, boolean simulate) {
        if (amount == 0)
            return ItemStack.EMPTY;

        ItemStack existing = this.stack;

        if (existing.isEmpty())
            return ItemStack.EMPTY;

        int toExtract = Math.min(amount, existing.getMaxStackSize());

        if (existing.getCount() <= toExtract) {
            if (!simulate) {
                ItemStack copy = existing.copy();
                this.stack.setCount(0);
                onContentsChanged();
                return copy;
            } else {
                return existing.copy();
            }
        } else {
            if (!simulate) {
                this.stack.setCount(this.stack.getCount() - amount);
                onContentsChanged();
            }

            return ItemHandlerHelper.copyStackWithSize(existing, toExtract);
        }
    }

    @Override
    public int getSlotLimit(int slot) {
        return maxCount;
    }

    @Override
    public boolean isItemValid(int slot, @Nonnull ItemStack stack) {
        return isItemValid(stack);
    }

    public boolean isItemValid(@Nonnull ItemStack stack) {
        return stack.getItem().equals(this.stack.getItem());
    }

    public void setStack(ItemStack stack) {
        this.stack = stack;
    }

    @Override
    public CompoundNBT serializeNBT() {
        CompoundNBT itemTag = new CompoundNBT();
        if (!stack.isEmpty()) {
            itemTag.putString("Item", stack.getItem().getRegistryName().toString());
            itemTag.putInt("Count", stack.getCount());

            if (stack.getTag() != null) {
                itemTag.put("Tag", stack.getTag().copy());
            }

            CompoundNBT nbt = stack.serializeNBT();

            if (nbt != null && !nbt.isEmpty()) {
                itemTag.put("NBT", nbt);
            }
        }

        CompoundNBT nbt = new CompoundNBT();
        nbt.put("Item", itemTag);
        nbt.putInt("MaxCount", maxCount);
        return nbt;
    }

    @Override
    public void deserializeNBT(CompoundNBT nbt) {
        maxCount = nbt.contains("MaxCount", Constants.NBT.TAG_INT) ? nbt.getInt("MaxCount") : ModConfig.MAX_COUNT.get();
        CompoundNBT item = nbt.getCompound("Item");
        stack = new ItemStack(ForgeRegistries.ITEMS.getValue(new ResourceLocation(item.getString("Item"))), item.getInt("Count"));
        CompoundNBT tag = nbt.getCompound("Tag");

        if (!tag.isEmpty()) {
            stack.setTag(tag);
        }

        CompoundNBT nbt1 = nbt.getCompound("NBT");

        if (!nbt1.isEmpty()) {
            stack.deserializeNBT(nbt1);
        }

        onLoad();
    }

    protected void onLoad() {

    }

    protected void onContentsChanged() {
        onContentsChanged.accept(stack, getMaxCount());
    }

    public int getMaxCount() {
        return maxCount;
    }
}
